package com.ckx.config.dao;

import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.core.date.DateField;
import org.dromara.hutool.core.date.DateTime;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Assert;

import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class DateShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {

    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    @Override
    public String getType() {
        return "dateSharding";
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        Map<String, Collection<Comparable<?>>> columnNameAndShardingValuesMap = shardingValue.getColumnNameAndShardingValuesMap();
        Map<String, Range<Comparable<?>>> columnNameAndRangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();

        if (!columnNameAndRangeValuesMap.isEmpty()) {
            return doShardingRange(availableTargetNames, shardingValue);
        }

        Collection<Comparable<?>> idValue = columnNameAndShardingValuesMap.get("id");
        Collection<Comparable<?>> dateValue = columnNameAndShardingValuesMap.get("create_time");


        if (idValue != null) {

            return idValue.stream().map(item -> {
                Long id = (Long) item;
                return getTable(logicTableName, getDateFromId(id));
            }).collect(Collectors.toList());
        }

        if (dateValue != null) {

            return dateValue.stream().map(item -> {
                Date creteTime = (Date) item;
                return getTable(logicTableName, creteTime);
            }).collect(Collectors.toList());
        }

        return Lists.newArrayList();
    }

    private String getTable(String logicTableName, Date creteTime) {
        String tableSuffix = DateUtil.toLocalDateTime(creteTime).format(dateTimeFormatter);
        return logicTableName + "_" + tableSuffix;
    }


    private List<String> doShardingRange(Collection<String> availableTargetNames, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
        Map<String, Range<Comparable<?>>> columnNameAndRangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();
        String logicTableName = shardingValue.getLogicTableName();

        Range<Comparable<?>> idRange = columnNameAndRangeValuesMap.get("id");
        Assert.isNull(idRange, "id 不支持范围查询");

        Range<Comparable<?>> createTimeRange = columnNameAndRangeValuesMap.get("create_time");
        Date lowerDate = (Date) createTimeRange.lowerEndpoint();
        Date upperDate = (Date) createTimeRange.upperEndpoint();

        DateTime tmpTime = DateUtil.beginOfDay(lowerDate);
        DateTime finalDate = DateUtil.beginOfDay(upperDate);

        List<String> tableList = new ArrayList<>(20);

        while (tmpTime.compareTo(finalDate) <= 0) {
            String dateStr = DateUtil.format(tmpTime, "yyyyMMdd");
            tmpTime = DateUtil.offset(tmpTime, DateField.DAY_OF_YEAR, 1);
            String tableName = logicTableName + "_" + dateStr;
            if (availableTargetNames.contains(tableName)) {
                tableList.add(tableName);
            }
        }

        return tableList;
    }

    private Date getDateFromId(long id) {
        long generateDateTime = IdUtil.getSnowflake().getGenerateDateTime(id);
        return new Date(generateDateTime);
    }

}